﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections;
using System.Xml;
using System.Data.SqlClient;
using WindowsFormsApplication1.RebornLogin;
using System.Diagnostics;
using WindowsFormsApplication1.TransferCharacterRequests;
using WindowsFormsApplication1.EnterGameRequests;
using WindowsFormsApplication1.WhoRequests;

namespace WindowsFormsApplication1
{
    public partial class PrimaryServer : Form
    {
        public const string connectionString = "Server=DOLEMITE;Initial Catalog=RPGRebornData;UID=sa;PWD=6vinuziy";

        //Main server socket for new connections
        private Socket socket_ServerConnect = null;
        private bool socket_ServerConnectIsListening = false;

        private Socket socket_PolicyConnect = null;
        private bool socket_PolicyConnectIsListening = false;

        private Socket socket_LoginConnect = null;
        private bool socket_LoginConnectIsListening = false;

        public static PrimaryServer instance;

        public PrimaryServer()
        {
            instance = this;

            InitializeComponent();
            GetIP();
            GetWorlds();

            List<ServerSocketData> servers = new List<ServerSocketData>();
            servers.Add(new ServerSocketData(null));
            ComboBox_WorldServerSelect.DisplayMember = "server";
            ComboBox_WorldServerSelect.DataSource = servers;
        }

        private void GetWorlds()
        {
            SqlConnection MyCon = new SqlConnection(PrimaryServer.connectionString);
            SqlCommand SQLCom = new SqlCommand("MapNames_SelectAllActive", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;

            MyCon.Open();
            SqlDataReader SDR = SQLCom.ExecuteReader();
            List<WorldMapData> worldsTmp = new List<WorldMapData>();
            while (SDR.Read())
            {
                for (int x = 1; x <= 4; x++)
                {
                    WorldMapData wmd = new WorldMapData();
                    wmd.MapID = int.Parse(SDR["MapID"].ToString());
                    wmd.StartMapID = int.Parse(SDR["StartMapID"].ToString());
                    wmd.StartMapX = int.Parse(SDR["StartMapX"].ToString());
                    wmd.StartMapY = int.Parse(SDR["StartMapY"].ToString());

                    wmd.MapDisplayName = SDR["MapDisplayName"].ToString();
                    wmd.MapName = SDR["MapName"].ToString();
                    wmd.InstanceID = x;

                    worldsTmp.Add(wmd);
                }
            }
            SDR.Close();
            SDR.Dispose();
            MyCon.Close();
            MyCon.Dispose();

            BindingList<WorldMapData> worlds = new BindingList<WorldMapData>();
            for (int x = 1; x <= 4; x++)
            {
                foreach (WorldMapData wmd in worldsTmp)
                {
                    if (wmd.InstanceID == x)
                    {
                        Managers.worldsManager.AddWorld(wmd);
                        worlds.Add(wmd);
                    }
                }
            }

            DataGrid_Worlds.DataSource = worlds;
        }

        //This will get the servers IP address.... for now just manually set it
        private void GetIP()
        {
            String strHostName = Dns.GetHostName();

            // Find host by name
            IPHostEntry iphostentry = Dns.GetHostEntry(strHostName);

            List<string> IPAddresses = new List<string>();
            List<string> IPAddresses2 = new List<string>();
            List<string> IPAddresses3 = new List<string>();

            // Grab the first IP addresses
            foreach (IPAddress ipaddress in iphostentry.AddressList)
            {
                IPAddresses.Add(ipaddress.ToString());
                IPAddresses2.Add(ipaddress.ToString());
                IPAddresses3.Add(ipaddress.ToString());
            }
            this.ComboBox_IPs.DataSource = IPAddresses;
            this.ComboBox_LoginIP.DataSource = IPAddresses2;
            this.ComboBox_PolicyIP.DataSource = IPAddresses3;
        }

        private void Button_Listening_Click(object sender, EventArgs e)
        {
            // Check the port value
            if (TextBox_Port.Text == "")
            {
                MessageBox.Show("Please enter a Port Number");
                return;
            }
            string portStr = this.TextBox_Port.Text;
            int port = Convert.ToInt32(portStr);

            IPAddress ip = IPAddress.Parse(this.ComboBox_IPs.Text);

            // Create the listening socket...
            socket_ServerConnect = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);


            IPEndPoint ipLocal = new IPEndPoint(ip, port);
            // Bind to local IP Address...
            socket_ServerConnect.Bind(ipLocal);
            // Start listening...
            socket_ServerConnect.Listen(32);
            // Create the call back for any client connections...
            socket_ServerConnect.BeginAccept(new AsyncCallback(onServerConnect), null);
            socket_ServerConnectIsListening = true;

            this.Invoke((Action)updateControls);
        }

        // This is the call back function, which will be invoked when a client is connected
        public void onServerConnect(IAsyncResult asyn)
        {
            try
            {
                Socket workerSocket = socket_ServerConnect.EndAccept(asyn);
                //Interlocked.Increment(ref totalServersConnected);

                //Add client socket to list
                ServerSocketData serverSocketData = new ServerSocketData(workerSocket);
                Managers.socketConnectionsManager.AddServerSocket(serverSocketData);

                //Start Waiting for data
                WaitForServerData(serverSocketData);

                //main socket can go back to listening for connections
                socket_ServerConnect.BeginAccept(new AsyncCallback(onServerConnect), null);

                this.Invoke((Action)updateControls);
            }
            catch (ObjectDisposedException)
            {
                System.Diagnostics.Debugger.Log(0, "1", "\n OnClientConnection: Socket has been closed\n");
            }
            catch (SocketException se)
            {
                MessageBox.Show(se.Message);
            }
        }

        // Start waiting for data from the server
        public void WaitForServerData(ServerSocketData socketPacket)
        {
            socketPacket.dataBuffer = new byte[1024];

            //socketPacket is just an object that gets passed around with the AsyncCalls 
            //to let us determine which client is sending us data
            socketPacket.socket.BeginReceive(socketPacket.dataBuffer, 0, socketPacket.dataBuffer.Length,
                SocketFlags.None, new AsyncCallback(onServerDataReceived), socketPacket);
        }

        public void onServerDataReceived(IAsyncResult asyn)
        {
            ServerSocketData socketPacket = (ServerSocketData)asyn.AsyncState;

            string allData = "";

            try
            {
                //Get Number of chars written to socket
                int iRx = socketPacket.socket.EndReceive(asyn);
                //Create char array to hold data
                char[] chars = new char[iRx];
                // Extract the characters as a buffer
                Decoder d = Encoding.UTF8.GetDecoder();
                d.GetChars(socketPacket.dataBuffer, 0, iRx, chars, 0);
                // Put data into string
                String szData = new String(chars);

                //Server Disconnect
                if (szData == "")
                {
                    closeServerSocket(socketPacket);
                    return;
                }

                while (socketPacket.socket.Available > 0)
                {
                    byte[] buffer = new byte[1024];
                    iRx = socketPacket.socket.Receive(buffer);
                    chars = new char[iRx];

                    d.GetChars(buffer, 0, iRx, chars, 0);
                    szData = szData + new String(chars);
                }

                socketPacket.AppendData(szData);

                allData = socketPacket.getRawData();

                string message = socketPacket.getMessage();
                while (message != "")
                {
                    XmlDocument xml = new XmlDocument();
                    xml.LoadXml(message);

                    if (xml.FirstChild.Name == "clientport")
                    {
                        int portnumber = int.Parse(xml.FirstChild.Attributes["portnumber"].Value.ToString());
                        socketPacket.clientConnectPort = portnumber;

                        this.Invoke((Action)updateControls);
                    }
                    else if (xml.FirstChild.Name == "clientexists_result")
                    {
                        int userid = int.Parse(xml.FirstChild.Attributes["userid"].Value.ToString());
                        string result = xml.FirstChild.Attributes["result"].Value.ToString();

                        Managers.loginManager.processLoginStatusResult(socketPacket, userid, result);
                    }
                    else if (xml.FirstChild.Name == "ownedworlds")
                    {
                        Managers.worldsManager.UpdateFromXML(socketPacket, message);
                        this.Invoke((Action)updateControls);
                    }
                    else if (xml.FirstChild.Name == "pendingclient_result")
                    {
                        bool result = bool.Parse(xml.FirstChild.Attributes["result"].Value.ToString());
                        int userid = int.Parse(xml.FirstChild.Attributes["userid"].Value.ToString());

                        Managers.enterGameManager.ProcessEnterGameResult(userid, result);
                    }
                    else if (xml.FirstChild.Name == "transfercharacter")
                    {
                        int mapid = int.Parse(xml.FirstChild.Attributes["mapid"].Value.ToString());
                        int instance = int.Parse(xml.FirstChild.Attributes["instance"].Value.ToString());
                        int characterid = int.Parse(xml.FirstChild.Attributes["characterid"].Value.ToString());
                        int mapx = int.Parse(xml.FirstChild.Attributes["mapx"].Value.ToString());
                        int mapy = int.Parse(xml.FirstChild.Attributes["mapy"].Value.ToString());
                        int userid = int.Parse(xml.FirstChild.Attributes["userid"].Value.ToString());

                        ServerSocketData sendToServer = Managers.worldsManager.GetServer(mapid, instance);

                        //send failure to requesting server
                        if (sendToServer.server == "Offline")
                        {
                            string replyMessage = "<transfercharacter_result userid=\"" + userid.ToString() + "\" error=\"" + "Map is unavailable" + "\" uid=\"" + "" + "\" port=\"" + "-1" + "\" />";
                            SocketConnectionsManager.sendToServer(socketPacket, replyMessage);
                        }
                        //Attempt to set up character on new server
                        else
                        {
                            TransferCharacterRequest transCharRequest = new TransferCharacterRequest();
                            transCharRequest.characterID = characterid;
                            transCharRequest.userID = userid;
                            transCharRequest.MapID = mapid;
                            transCharRequest.Instance = instance;
                            transCharRequest.MapX = mapx;
                            transCharRequest.MapY = mapy;
                            transCharRequest.uid = System.Guid.NewGuid().ToString();
                            transCharRequest.transferFromServer = socketPacket;
                            transCharRequest.transferToServer = sendToServer;

                            //Try to send the transfer request to server character is moving to
                            if (Managers.transferCharacterManager.SendTransferRequest(transCharRequest) == false)
                            {
                                string replyMessage = "<transfercharacter_result characterid=\"" + characterid.ToString() + "\" mapid=\"" + mapid.ToString() + "\" instance=\"" + instance.ToString() + "\" port=\"" + "Offline" + "\" />";
                                SocketConnectionsManager.sendToServer(socketPacket, replyMessage);
                            }
                        }
                    }
                    else if (xml.FirstChild.Name == "transferclient_result")
                    {
                        bool result = bool.Parse(xml.FirstChild.Attributes["result"].Value.ToString());
                        int userid = int.Parse(xml.FirstChild.Attributes["userid"].Value.ToString());

                        Managers.transferCharacterManager.ProcessTransferCharacterResult(userid, result);
                    }
                    else if (xml.FirstChild.Name == "tellrequestWS")
                    {
                        string tellguid = xml.FirstChild.Attributes["tellguid"].Value.ToString();
                        string fromname = xml.FirstChild.Attributes["fromname"].Value.ToString();
                        string toname = xml.FirstChild.Attributes["toname"].Value.ToString();
                        string msg = xml.FirstChild["txt"].InnerText;
                        string itemlinks = xml.FirstChild["itemlinks"].OuterXml;

                        Managers.tellManager.sendTellRequest(socketPacket, tellguid, fromname, toname, msg, itemlinks);
                    }
                    else if (xml.FirstChild.Name == "tellrequestresultPS")
                    {
                        string tellguid = xml.FirstChild.Attributes["tellguid"].Value.ToString();
                        string fromname = xml.FirstChild.Attributes["fromname"].Value.ToString();
                        string toname = xml.FirstChild.Attributes["toname"].Value.ToString();
                        bool messagesuccessfull = bool.Parse(xml.FirstChild.Attributes["messagesuccessfull"].Value.ToString());

                        Managers.tellManager.processResult(socketPacket, tellguid, fromname, toname, messagesuccessfull);
                    }
                    else if (xml.FirstChild.Name == "karmanotification")
                    {
                        int characterId = int.Parse(xml.FirstChild.Attributes["characterid"].Value.ToString());
                        Managers.socketConnectionsManager.sendToAllServersExcluding(socketPacket, "<karmanotification characterid=\"" + characterId.ToString() + "\" />");
                    }
                    else if (xml.FirstChild.Name == "friendonline")
                    {
                        string characterId = xml.FirstChild.Attributes["id"].Value.ToString();

                        //The sending server will have already notified its players, so exclude the sender.
                        Managers.socketConnectionsManager.sendToAllServersExcluding(socketPacket, "<friendonline id=\"" + characterId + "\" />");
                    }
                    else if (xml.FirstChild.Name == "sendchanneljoin" || xml.FirstChild.Name == "sendchannelleave")
                    {
                        string channel = xml.FirstChild.Attributes["channel"].Value.ToString();
                        string from = xml.FirstChild.Attributes["from"].Value.ToString();

                        Managers.socketConnectionsManager.sendToAllServersExcluding(socketPacket, xml.InnerXml);
                    }
                    else if (xml.FirstChild.Name == "sendchannelmessage")
                    {
                        string channel = xml.FirstChild.Attributes["channel"].Value.ToString();
                        string from = xml.FirstChild.Attributes["from"].Value.ToString();

                        string msg = xml["sendchannelmessage"]["txt"].InnerText;
                        string itemLinksXml = xml["sendchannelmessage"]["itemlinks"].OuterXml;

                        Managers.socketConnectionsManager.sendToAllServersExcluding(socketPacket, "<sendchannelmessage channel=\"" + channel + "\" from=\"" + from + "\" ><txt>" + Managers.escapeXmlText(msg) + "</txt>" + itemLinksXml + "</sendchannelmessage>");
                    }
                    else if (xml.FirstChild.Name == "globalmessage")
                    {
                        string gmessage = xml.FirstChild["txt"].InnerText;
                        string itemLinksXml = xml.FirstChild["itemlinks"].OuterXml;

                        Managers.socketConnectionsManager.sendToAllServersExcluding(socketPacket, "<globalmessage><txt>" + Managers.escapeXmlText(gmessage) + "</txt>" + itemLinksXml + "</globalmessage>");
                    }
                    else if (xml.FirstChild.Name == "globalwhorequest")
                    {
                        int characterId = int.Parse(xml.FirstChild.Attributes["characterid"].Value.ToString());

                        Managers.whoRequestManager.sendWhoRequest(new WhoRequest(socketPacket, characterId));
                    }
                    else if (xml.FirstChild.Name == "globalwhoresult")
                    {
                        int characterId = int.Parse(xml.FirstChild.Attributes["characterid"].Value.ToString());

                        Managers.whoRequestManager.processWhoResult(socketPacket, characterId, xml.InnerXml);
                    }
                    else if (xml.FirstChild.Name == "newmail")
                    {
                        string characterId = xml.FirstChild.Attributes["characterid"].Value.ToString();

                        //Do not send back to origionating server.
                        Managers.socketConnectionsManager.sendToAllServersExcluding(socketPacket, "<newmail characterid=\"" + characterId + "\" />");
                    }
                    else if (xml.FirstChild.Name == "friendoffline")
                    {
                        string characterId = xml.FirstChild.Attributes["id"].Value.ToString();

                        Managers.socketConnectionsManager.sendToAllServersExcluding(socketPacket, "<friendoffline id=\"" + characterId + "\" />");
                    }
                    //World server requests primary to look for friends on all servers                       
                    else if (xml.FirstChild.Name == "findfriendsWS")
                    {
                        int characterId = int.Parse(xml.FirstChild.Attributes["friendsofId"].Value.ToString());

                        //Sends findfriendsPS to all world servers
                        Managers.findFriendsManager.sendFindFriendsRequests(socketPacket, characterId, message);
                    }
                    //World server responds to request from primary looking for friends
                    else if (xml.FirstChild.Name == "findfriendsPS")
                    {
                        int characterId = int.Parse(xml.FirstChild.Attributes["friendsofId"].Value.ToString());
                        Managers.findFriendsManager.processFindFriendsResult(socketPacket, characterId, message);
                    }

                    message = socketPacket.getMessage();
                }

                //Go back to listening
                WaitForServerData(socketPacket);
            }
            catch
            {
                closeServerSocket(socketPacket);
            }
        }

        private void closeServerSocket(ServerSocketData serverSocketData)
        {
            Managers.worldsManager.ServerOffline(serverSocketData);
            Managers.socketConnectionsManager.RemoveServerSocket(serverSocketData);
            serverSocketData.socket.Close();

            //Interlocked.Decrement(ref totalServersConnected);
            this.Invoke((Action)updateControls);
        }

        private void updateControls()
        {
            int serverConnections = Managers.socketConnectionsManager.CountServerSockets();
            Label_ServerConnections.Text = serverConnections.ToString();

            int clientConnections = Managers.socketConnectionsManager.CountClientSockets();
            Label_ClientConnections.Text = clientConnections.ToString();

            //Refresh Server List
            ServerSocketData selectedListItem = (ServerSocketData)this.ListBox_Servers.SelectedItem;
            this.ListBox_Servers.DataSource = null;
            this.ListBox_Servers.DisplayMember = "server";
            this.ListBox_Servers.DataSource = Managers.socketConnectionsManager.GetServerSocketsCpy();

            if (selectedListItem != null && Managers.socketConnectionsManager.ContainsServerSocket(selectedListItem))
                this.ListBox_Servers.SelectedItem = selectedListItem;
            else
                this.ListBox_Servers.SelectedItem = null;

            //Refresh Worlds Grid
            //DataGridViewSelectedRowCollection selectedRows = DataGrid_Worlds.SelectedRows;
            //List<string> SelectedIDs = new List<string>();
            //foreach (DataGridViewRow selectedRow in selectedRows)
            //    SelectedIDs.Add(selectedRow.Cells[0].Value.ToString());
            //List<int> ColumnWidths = new List<int>();
            //foreach (DataGridViewColumn dgc in DataGrid_Worlds.Columns)
            //    ColumnWidths.Add(dgc.Width);

            //DataGrid_Worlds.DataSource = null;
            //DataGrid_Worlds.DataSource = Managers.worldsManager.GetWorldsCpy();
            //DataGrid_Worlds.ClearSelection();
            //foreach (DataGridViewRow row in DataGrid_Worlds.Rows)
            //{
            //    foreach (string id in SelectedIDs)
            //    {
            //        if (row.Cells[0].Value.ToString() == id)
            //        {
            //            row.Selected = true;
            //            break;
            //        }
            //    }
            //}
            //for (int x = 0; x < DataGrid_Worlds.Columns.Count; x++)
            //    DataGrid_Worlds.Columns[x].Width = ColumnWidths[x];


            //Refresh World Server ComboBox
            ServerSocketData selectedServer = (ServerSocketData)this.ComboBox_WorldServerSelect.SelectedItem;
            ComboBox_WorldServerSelect.DataSource = null;
            ComboBox_WorldServerSelect.DisplayMember = "server";
            List<ServerSocketData> servers = Managers.socketConnectionsManager.GetServerSocketsCpy();
            servers.Insert(0, new ServerSocketData(null));
            ComboBox_WorldServerSelect.DataSource = servers;

            if (selectedServer != null && Managers.socketConnectionsManager.ContainsServerSocket(selectedServer))
                ComboBox_WorldServerSelect.SelectedItem = selectedServer;
            else if (selectedServer.server == "Offline")
                ComboBox_WorldServerSelect.SelectedIndex = 0;

            if (socket_ServerConnectIsListening)
            {
                Button_ServerStartListening.Enabled = false;
                Button_ServerStopListening.Enabled = true;

                this.ComboBox_IPs.Enabled = false;
                this.TextBox_Port.Enabled = false;
            }
            else
            {
                Button_ServerStartListening.Enabled = true;
                Button_ServerStopListening.Enabled = false;

                this.ComboBox_IPs.Enabled = true;
                this.TextBox_Port.Enabled = true;
            }
            if (socket_PolicyConnectIsListening)
            {
                this.Button_PolicyStartListening.Enabled = false;
                this.Button_PolicyStopListening.Enabled = true;

                ComboBox_PolicyIP.Enabled = false;
                TextBox_PolicyPort.Enabled = false;
            }
            else
            {
                this.Button_PolicyStartListening.Enabled = true;
                this.Button_PolicyStopListening.Enabled = false;

                ComboBox_PolicyIP.Enabled = true;
                TextBox_PolicyPort.Enabled = true;
            }
            if (socket_LoginConnectIsListening)
            {
                this.Button_LoginStartListening.Enabled = false;
                this.Button_LoginStopListening.Enabled = true;

                ComboBox_LoginIP.Enabled = false;
                TextBox_LoginPort.Enabled = false;
            }
            else
            {
                this.Button_LoginStartListening.Enabled = true;
                this.Button_LoginStopListening.Enabled = false;

                ComboBox_LoginIP.Enabled = true;
                TextBox_LoginPort.Enabled = true;
            }

            if (serverConnections > 0 && Button_ServerStartListening.Enabled == true)
                Button_CloseServerConnections.Enabled = true;
            else
                Button_CloseServerConnections.Enabled = false;

            if (clientConnections > 0 && Button_LoginStartListening.Enabled == true)
                Button_LoginCloseConnections.Enabled = true;
            else
                Button_LoginCloseConnections.Enabled = false;

            DataGrid_Worlds.Refresh();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (socket_ServerConnect != null)
            {
                socket_ServerConnect.Close();
                socket_ServerConnectIsListening = false;
            }

            this.Invoke((Action)updateControls);
        }

        private void Button_CloseServerConnections_Click(object sender, EventArgs e)
        {
            Managers.socketConnectionsManager.CloseAllServerConnections();
            this.Invoke((Action)updateControls);
        }

        private void Button_PolicyStartListening_Click(object sender, EventArgs e)
        {
            // Check the port value
            if (this.TextBox_PolicyPort.Text == "")
            {
                MessageBox.Show("Please enter a Port Number");
                return;
            }

            IPAddress ip = IPAddress.Parse(this.ComboBox_PolicyIP.Text);

            socket_PolicyConnect = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint ipLocal_p = new IPEndPoint(ip, int.Parse(this.TextBox_PolicyPort.Text));
            socket_PolicyConnect.Bind(ipLocal_p);
            socket_PolicyConnect.Listen(32);
            socket_PolicyConnect.BeginAccept(new AsyncCallback(onClientConnect_Policy), null);

            this.socket_PolicyConnectIsListening = true;
            this.Invoke((Action)updateControls);
        }

        private void onClientConnect_Policy(IAsyncResult asyn)
        {
            Debug.Print("Policy Connect");
            try
            {
                Socket workerSocket = socket_PolicyConnect.EndAccept(asyn);

                Debug.Print("Policy File Sent: 843");
                workerSocket.Send(System.Text.Encoding.ASCII.GetBytes("<?xml version=\"1.0\"?><!DOCTYPE cross-domain-policy SYSTEM \"/xml/dtds/cross-domain-policy.dtd\"><cross-domain-policy><site-control permitted-cross-domain-policies=\"all\" /><allow-access-from domain=\"*\" to-ports=\"843-850,2844\" /></cross-domain-policy>" + "\0"));
                workerSocket.Close(5);
            }
            catch { }
            finally
            {
                //policy socket can go back to listening for more connections
                socket_PolicyConnect.BeginAccept(new AsyncCallback(onClientConnect_Policy), null);
            }
        }


        private void Button_PolicyStopListening_Click(object sender, EventArgs e)
        {
            if (socket_PolicyConnect != null)
            {
                socket_PolicyConnect.Close();
                socket_PolicyConnectIsListening = false;
            }

            this.Invoke((Action)updateControls);
        }

        private void Button_LoginStartListening_Click(object sender, EventArgs e)
        {
            // Check the port value
            if (this.TextBox_LoginPort.Text == "")
            {
                MessageBox.Show("Please enter a Port Number");
                return;
            }
            int port = Convert.ToInt32(this.TextBox_LoginPort.Text);

            IPAddress ip = IPAddress.Parse(this.ComboBox_LoginIP.Text);

            // Create the listening socket...
            socket_LoginConnect = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);


            IPEndPoint ipLocal = new IPEndPoint(ip, port);
            // Bind to local IP Address...
            socket_LoginConnect.Bind(ipLocal);
            // Start listening...
            socket_LoginConnect.Listen(32);
            // Create the call back for any client connections...
            socket_LoginConnect.BeginAccept(new AsyncCallback(onLoginConnect), null);

            socket_LoginConnectIsListening = true;

            this.Invoke((Action)updateControls);
        }
        private void onLoginConnect(IAsyncResult asyn)
        {
            Socket workerSocket = null;
            ClientSocketData clientSocketData = null;

            Debug.Print("Client Connect");
            try
            {
                workerSocket = socket_LoginConnect.EndAccept(asyn);
                //Interlocked.Increment(ref totalServersConnected);

                //Add client socket to list
                clientSocketData = new ClientSocketData(workerSocket);
                Managers.socketConnectionsManager.AddClientSocket(clientSocketData);
                
                CloseClientSocketDelegate closeFunction = closeClientSocket;
                clientSocketData.closeSocketFunction = closeFunction;

                //Start Waiting for data
                WaitForClientData(clientSocketData);
                this.Invoke((Action)updateControls);

                if (CheckBox_LoginSound.Checked == true)
                {
                    System.Media.SoundPlayer sp = new System.Media.SoundPlayer();
                    sp.Stream = WindowsFormsApplication1.Properties.Resources.Chime2;
                    sp.Play();
                }
            }
            catch (Exception ex)
            {
                if (clientSocketData != null)
                    this.closeClientSocket(clientSocketData);
            }
            finally
            {
                //main socket can go back to listening for connections
                socket_LoginConnect.BeginAccept(new AsyncCallback(onLoginConnect), null);

                if (clientSocketData != null && clientSocketData.socket.Connected == false)
                    closeClientSocket(clientSocketData);
            }
        }
        // Start waiting for data from the server
        public void WaitForClientData(ClientSocketData socketPacket)
        {
            if (socketPacket.socket.Connected == false)
            {
                closeClientSocket(socketPacket);
                return;
            }

            try
            {
                socketPacket.dataBuffer = new byte[1024];

                //socketPacket is just an object that gets passed around with the AsyncCalls 
                //to let us determine which client is sending us data
                socketPacket.socket.BeginReceive(socketPacket.dataBuffer, 0, socketPacket.dataBuffer.Length,
                    SocketFlags.None, new AsyncCallback(onClientDataReceived), socketPacket);
            }
            catch (Exception ex)
            {
                closeClientSocket(socketPacket);
            }
        }

        public void onClientDataReceived(IAsyncResult asyn)
        {
            Debug.Print("Client Data Recieved");
            ClientSocketData socketPacket = (ClientSocketData)asyn.AsyncState;

            if (socketPacket.socket.Connected == false)
            {
                closeClientSocket(socketPacket);
                return;
            }

            try
            {
                //Get Number of chars written to socket
                int iRx = socketPacket.socket.EndReceive(asyn);
                //Create char array to hold data
                char[] chars = new char[iRx];
                // Extract the characters as a buffer
                Decoder d = Encoding.UTF8.GetDecoder();
                d.GetChars(socketPacket.dataBuffer, 0, iRx, chars, 0);
                // Put data into string
                String szData = new String(chars);

                while (socketPacket.socket.Available > 0)
                {
                    byte[] buffer = new byte[1024];
                    iRx = socketPacket.socket.Receive(buffer);
                    chars = new char[iRx];

                    d.GetChars(buffer, 0, iRx, chars, 0);
                    szData = szData + new String(chars);
                }

                //Client Disconnect
                if (szData == "\0" || szData == "\0\0" || szData == "")
                {
                    closeClientSocket(socketPacket);
                    return;
                }

                XmlDocument xml = new XmlDocument();
                xml.LoadXml(szData);

                if (xml.FirstChild.Name == "policy-file-request")
                {
                    socketPacket.socket.SendPolicy();
                    socketPacket.socket.Close();
                    return;
                }

                if (xml.FirstChild.Name == "login")
                {
                    string username = xml.ChildNodes[0].ChildNodes[0].InnerText;
                    string password = xml.ChildNodes[0].ChildNodes[1].InnerText;

                    string clientId = "";
                    try
                    {
                        clientId = xml.ChildNodes[0].ChildNodes[3].InnerText;
                    }
                    catch
                    {
                        clientId = "";
                    }

                    string clientversion = tryGetVersion(xml);

                    Managers.loginManager.Login(username, password, clientId, socketPacket, clientversion);
                    //Go back to listening
                    WaitForClientData(socketPacket);
                    return;
                }

                //Disconnect the socket if user is not logged in, but is sending data
                if (socketPacket.UserID == 0)
                {
                    closeClientSocket(socketPacket);
                    return;
                }

                if (xml.FirstChild.Name == "passwordreset")
                {
                    string newpassword = xml.FirstChild.Attributes["newpassword"].Value.ToString();

                    SqlConnection MyCon = new SqlConnection(PrimaryServer.connectionString);
                    SqlCommand SQLCom = new SqlCommand("Users_ChangePasswordByID", MyCon);
                    SQLCom.CommandType = System.Data.CommandType.StoredProcedure;

                    SQLCom.Parameters.AddWithValue("@ID", socketPacket.UserID);
                    SQLCom.Parameters.AddWithValue("@NewPassword", newpassword);
                    MyCon.Open();
                    SQLCom.ExecuteNonQuery();
                    MyCon.Close();
                }
                else if (xml.FirstChild.Name == "selectmapnames")
                    Managers.loginManager.MapNames_Select(socketPacket);
                else if (xml.FirstChild.Name == "selectcharacters")
                    Managers.loginManager.Characters_Select(socketPacket);
                else if (xml.FirstChild.Name == "charactersinsert")
                {
                    string name = xml.FirstChild.Attributes["name"].Value.ToString();
                    string img = xml.FirstChild.Attributes["img"].Value.ToString();
                    string corpseimg = xml.FirstChild.Attributes["corpseimg"].Value.ToString();
                    string gender = xml.FirstChild.Attributes["gender"].Value.ToString();
                    int Str = int.Parse(xml.FirstChild.Attributes["str"].Value.ToString());
                    int Dex = int.Parse(xml.FirstChild.Attributes["dex"].Value.ToString());
                    int Agi = int.Parse(xml.FirstChild.Attributes["agi"].Value.ToString());
                    int Int = int.Parse(xml.FirstChild.Attributes["int"].Value.ToString());
                    int Wis = int.Parse(xml.FirstChild.Attributes["wis"].Value.ToString());

                    string meleeskill = xml.FirstChild.Attributes["meleeskill"].Value.ToString();

                    Managers.loginManager.Characters_Insert(socketPacket, name, corpseimg, img, gender, Str, Dex, Agi, Int, Wis, meleeskill);
                }
                else if (xml.FirstChild.Name == "cancreatecharacter")
                {
                    Managers.loginManager.CanCreateCharacter(socketPacket);
                }
                else if (xml.FirstChild.Name == "charactersdelete")
                {
                    int characterid = int.Parse(xml.FirstChild.Attributes["characterid"].Value.ToString());

                    Managers.loginManager.Characters_Delete(socketPacket, characterid);
                }
                else if (xml.FirstChild.Name == "charactersrename")
                {
                    int characterid = int.Parse(xml.FirstChild.Attributes["characterid"].Value.ToString());
                    string name = xml.FirstChild.Attributes["name"].Value.ToString();

                    Managers.loginManager.Characters_Rename(socketPacket, characterid, name);
                }
                else if (xml.FirstChild.Name == "logout")
                {
                    string replyMsg = "<logout_result>" + "true" + "</logout_result>";

                    socketPacket.socket.BeginSend(replyMsg);
                    socketPacket.socket.Close();
                }
                else if (xml.FirstChild.Name == "entergame")
                {
                    int characterid = int.Parse(xml.FirstChild.Attributes["characterid"].Value.ToString());
                    int instance = int.Parse(xml.FirstChild.Attributes["instance"].Value.ToString());

                    int UserID;
                    int MapID;
                    int Instance;
                    int MapX;
                    int MapY;

                    //Get selected characters current position
                    Managers.loginManager.GetCharacterPosition(characterid, out UserID, out MapID, out Instance, out MapX, out MapY);

                    //Should never happen, but if someone tries to connect to a character that they do not own, drop connection
                    if (UserID != socketPacket.UserID)
                        closeClientSocket(socketPacket);
                    else
                    {
                        //If character has changed instances, reset the starting position
                        if (instance != Instance)
                        {
                            Instance = instance;
                            int NewMapID;
                            Managers.worldsManager.GetStartPosition(MapID, out MapX, out MapY, out NewMapID);
                            MapID = NewMapID;
                        }
                        //Send the server the client will be connecting to a entergame request
                        ServerSocketData sendToServer = Managers.worldsManager.GetServer(MapID, Instance);
                        string errorMessage = "";
                        if (sendToServer.server != "Offline")
                        {
                            EnterGameRequest enterGameRequest = new EnterGameRequest(socketPacket);
                            enterGameRequest.clientSocketData = socketPacket;
                            enterGameRequest.transferToServer = sendToServer;
                            enterGameRequest.characterID = characterid;
                            enterGameRequest.MapID = MapID;
                            enterGameRequest.Instance = Instance;
                            enterGameRequest.MapX = MapX;
                            enterGameRequest.MapY = MapY;
                            enterGameRequest.uid = System.Guid.NewGuid().ToString();

                            //Should never get here, just incase someone is hacking
                            if (Managers.enterGameManager.SendEnterGameRequest(enterGameRequest) == false)
                                errorMessage = "Unable to send your request to world server, Either you have a pending request or the server is unavailable. If the problem persists, please email Webmaster@RpgReborn.com";
                        }
                        else
                            errorMessage = "World server is offline, please try a different instance.";

                        //Send failure to client
                        if (errorMessage != "")
                        {
                            string xmlMessage = "<entergameresult error=\"" + errorMessage + "\" />";
                            socketPacket.socket.BeginSend(xmlMessage);
                        }
                    }
                }

                //Go back to listening
                WaitForClientData(socketPacket);
            }
            catch (Exception ex)
            {
                closeClientSocket(socketPacket);
            }
        }

        private string tryGetVersion(XmlDocument xml)
        {
            try
            {
                return xml.ChildNodes[0].ChildNodes[2].InnerText;
            }
            catch
            {
                return "";
            }
        }

        delegate void CloseClientSocketDelegate(ClientSocketData clientSocketData);
        public void closeClientSocket(ClientSocketData clientSocketData)
        {
            clientSocketData.killLoginTimout();
            clientSocketData.killDropConnectionTimer();

            Managers.socketConnectionsManager.RemoveClientSocket(clientSocketData);

            this.Invoke((Action)updateControls);

            try
            {
                clientSocketData.socket.Close();
            }
            catch { }
        }

        private void Button_LoginStopListening_Click(object sender, EventArgs e)
        {
            if (socket_LoginConnect != null)
            {
                socket_LoginConnect.Close();
                socket_LoginConnectIsListening = false;
            }

            this.Invoke((Action)updateControls);
        }

        private void Button_LoginCloseConnections_Click(object sender, EventArgs e)
        {
            Managers.socketConnectionsManager.CloseAllClientConnections();
            this.Invoke((Action)updateControls);
        }

        private void Button_MoveWorlds_Click(object sender, EventArgs e)
        {
            List<WorldMapData> worldsToUpdate = new List<WorldMapData>();
            ServerSocketData changeToServer = (ServerSocketData)ComboBox_WorldServerSelect.SelectedItem;
            foreach (DataGridViewRow row in DataGrid_Worlds.SelectedRows)
            {
                WorldMapData wmd = (WorldMapData)row.DataBoundItem;
                worldsToUpdate.Add(wmd);
            }
            Managers.worldsManager.ChangeServer(worldsToUpdate, changeToServer);

            DataGrid_Worlds.Refresh();
            //Button_MoveWorlds.Enabled = false;
        }

        private void DataGrid_Worlds_SelectionChanged(object sender, EventArgs e)
        {
            if (DataGrid_Worlds.SelectedRows.Count == 0)
                Button_MoveWorlds.Enabled = false;
            else
                Button_MoveWorlds.Enabled = true;
        }
    }
}
